﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.IO;
using UnityEngine;
//using System.Drawing.Drawing2D;

public class FM_Tuplet
{
    private int index;
    private List<FM_BaseNote> notes;
    private int size;
    private int position; // 0 - above, 1 - below
    private FM_Score score;

    public FM_Tuplet(FM_Score score, int size, int index, int position)
    {
        notes = new List<FM_BaseNote>();
        this.size = size;
        this.index = index;
        this.position = position;
        this.score = score;
    }

    public void AddNote(FM_BaseNote note)
    {
        notes.Add(note);
    }
    public void Draw(ScoreCanvas canvas)
    {
        if (!notes[0].blurred && !notes[0].visible) return;

        //if (n[0].blurred)
        //    score.Font.SetMaskFilter(new BlurMaskFilter(15, BlurMaskFilter.Blur.NORMAL));
        //else
        //    score.Font.SetMaskFilter(null);

        float x, xe, y, ye;
        float StaveLineHalfWidth = FM_Const.dpTOpx(0.25f);
        int EndIndex = notes.Count - 1;
        x = notes[0].Left() + notes[0].WidthAccidental() - 0.5f * score.GetDistanceBetweenStaveLines();
        xe = notes[EndIndex].Right() + 0.5f * score.GetDistanceBetweenStaveLines();

        bool beam = false;
        if ((notes[0] is FM_Note && ((FM_Note)notes[0]).beam) && (notes[EndIndex] is FM_Note && ((FM_Note)notes[EndIndex]).beam))
            beam = true;

        if (notes[0] is FM_Pause)
            beam = false;
        if (notes[EndIndex] is FM_Pause)
            beam = false;

        if (position == 0)
        {
            if (notes[0].stem_up) x = x + score.GetDistanceBetweenStaveLines();
            y = notes[0].Top();
            if (notes[0].Bottom() < y) y = notes[0].Bottom();
            ye = notes[EndIndex].Top();
            if (notes[EndIndex].Bottom() < ye) ye = notes[EndIndex].Bottom();
            y = y + 0.5f * score.GetDistanceBetweenStaveLines();
            ye = ye + 0.5f * score.GetDistanceBetweenStaveLines();

            if (!beam)
            {
                if (ye > y)
                {
                    float fslope = FM_Const.Slope(0, x, y, xe, ye);
                    ye = FM_Const.GetY2(fslope, x, y, xe);
                }
                else
                {
                    float fslope = FM_Const.Slope(0, xe, ye, x, y);
                    y = FM_Const.GetY2(fslope, xe, ye, x);
                }

                float yMiddleMin = notes[1].Top();
                if (notes[1].Bottom() < yMiddleMin) yMiddleMin = notes[1].Bottom();

                for (int i = 2; i < notes.Count - 1; i++)
                {
                    float yMiddle = notes[i].Top();
                    if (notes[i].Bottom() < yMiddle) yMiddle = notes[i].Bottom();
                    if (yMiddle < yMiddleMin) yMiddleMin = yMiddle;
                }

                if ((y + ye) / 2 > yMiddleMin)
                {
                    float diff = (y + ye) / 2 - yMiddleMin;
                    y = y - diff;
                    ye = ye - diff;
                }

                y = y - 0.5f * score.GetDistanceBetweenStaveLines();
                ye = ye - 0.5f * score.GetDistanceBetweenStaveLines();
            }
            else
            {
                int i = 0;
                while (notes[i] is FM_Pause) i += 1;
                y = ((FM_Note)notes[i]).StemTopY;
                i = notes.Count - 1;
                while (notes[i] is FM_Pause) i -= 1;
                ye = ((FM_Note)notes[i]).StemTopY;
            }
        }
        else
        {
            if (!notes[EndIndex].stem_up) xe = xe - score.GetDistanceBetweenStaveLines();

            y = notes[0].Top();
            if (notes[0].Bottom() > y) y = notes[0].Bottom();
            ye = notes[EndIndex].Top();
            if (notes[EndIndex].Bottom() > ye) ye = notes[EndIndex].Bottom();
            y = y - 0.5f * score.GetDistanceBetweenStaveLines();
            ye = ye - 0.5f * score.GetDistanceBetweenStaveLines();

            if (!beam)
            {
                if (ye < y)
                {
                    float fslope = FM_Const.Slope(0, x, y, xe, ye);
                    ye = FM_Const.GetY2(fslope, x, y, xe);
                }
                else
                {
                    float fslope = FM_Const.Slope(0, xe, ye, x, y);
                    y = FM_Const.GetY2(fslope, xe, ye, x);
                }

                float yMiddleMin = notes[1].Bottom();
                if (notes[1].Top() > yMiddleMin) yMiddleMin = notes[1].Top();

                for (int i = 2; i < notes.Count - 1; i++)
                {
                    float yMiddle = notes[i].Bottom();
                    if (notes[i].Top() > yMiddle) yMiddle = notes[i].Top();
                    if (yMiddle > yMiddleMin) yMiddleMin = yMiddle;
                }

                if ((y + ye) / 2 < yMiddleMin)
                {
                    float diff = (y + ye) / 2 - yMiddleMin;
                    y = y - diff;
                    ye = ye - diff;
                }

                y = y + 0.5f * score.GetDistanceBetweenStaveLines();
                ye = ye + 0.5f * score.GetDistanceBetweenStaveLines();
            }
            else
            {
                int i = 0;
                while (notes[i] is FM_Pause) i += 1;
                if (((FM_Note)notes[i]).StemTopY != 0) y = ((FM_Note)notes[i]).StemTopY;
                i = notes.Count - 1;
                while (notes[i] is FM_Pause) i -= 1;
                if (((FM_Note)notes[i]).StemTopY != 0) ye = ((FM_Note)notes[i]).StemTopY;
                y = y - 0.6f * score.GetDistanceBetweenStaveLines();
                ye = ye - 0.6f * score.GetDistanceBetweenStaveLines();
            }
        }

        string text = FM_Const._3;
        if (size == 7) text = FM_Const._7;
        if (size == 6) text = FM_Const._6;
        if (size == 5) text = FM_Const._5;
        if (size == 4) text = FM_Const._4;
        if (size == 2) text = FM_Const._2;

        GraphicPath topPath;
        if (!beam)
        {
            if (position == 0)
            {
                canvas.DrawRect(x - StaveLineHalfWidth, y, x + StaveLineHalfWidth, y - score.GetDistanceBetweenStaveLines(), score.Font);
                canvas.DrawRect(xe - StaveLineHalfWidth, ye, xe + StaveLineHalfWidth, ye - score.GetDistanceBetweenStaveLines(), score.Font);
            }
            else
            {
                canvas.DrawRect(x - StaveLineHalfWidth, y, x + StaveLineHalfWidth, y + score.GetDistanceBetweenStaveLines(), score.Font);
                canvas.DrawRect(xe - StaveLineHalfWidth, ye, xe + StaveLineHalfWidth, ye + score.GetDistanceBetweenStaveLines(), score.Font);
            }
        }

        FM_Const.AdjustFont(score, text, 1);
        //score.Font.TextSize = 16;
        float w = score.Font.MeasureText(text);
        float middle1 = (x + xe) / 2 - w / 2 - score.GetDistanceBetweenStaveLines() / 2;
        float middle2 = (x + xe) / 2 + w / 2 + score.GetDistanceBetweenStaveLines() / 2;
        float slope = FM_Const.Slope(0, x, y - score.GetDistanceBetweenStaveLines(), xe, ye - score.GetDistanceBetweenStaveLines());

        float lineWidth = 1;
        if (!beam)
        {
            if (position == 0)
            {
                topPath = new GraphicPath();
                topPath.Reset();
                topPath.MoveTo(x, y - score.GetDistanceBetweenStaveLines() + 2 * StaveLineHalfWidth);
                topPath.LineTo(middle1, slope * (middle1 - x) + y - score.GetDistanceBetweenStaveLines() + 2 * StaveLineHalfWidth);
                topPath.LineTo(middle1, slope * (middle1 - x) + y - score.GetDistanceBetweenStaveLines());
                topPath.LineTo(x, y - score.GetDistanceBetweenStaveLines());
                topPath.LineTo(x, y - score.GetDistanceBetweenStaveLines() + 2 * StaveLineHalfWidth);
                canvas.DrawPath(topPath, lineWidth);

                topPath = new GraphicPath();
                topPath.Reset();
                topPath.MoveTo(middle2, ye - score.GetDistanceBetweenStaveLines() - slope * (xe - middle2) + 2 * StaveLineHalfWidth);
                topPath.LineTo(xe, ye - score.GetDistanceBetweenStaveLines() + 2 * StaveLineHalfWidth);
                topPath.LineTo(xe, ye - score.GetDistanceBetweenStaveLines());
                topPath.LineTo(middle2, ye - score.GetDistanceBetweenStaveLines() - slope * (xe - middle2));
                topPath.LineTo(middle2, ye - score.GetDistanceBetweenStaveLines() - slope * (xe - middle2) + 2 * StaveLineHalfWidth);
                canvas.DrawPath(topPath, lineWidth);
            }
            else
            {
                topPath = new GraphicPath();
                topPath.Reset();
                topPath.MoveTo(x, y + score.GetDistanceBetweenStaveLines() - 2 * StaveLineHalfWidth);
                topPath.LineTo(middle1, slope * (middle1 - x) + y + score.GetDistanceBetweenStaveLines() - 2 * StaveLineHalfWidth);
                topPath.LineTo(middle1, slope * (middle1 - x) + y + score.GetDistanceBetweenStaveLines());
                topPath.LineTo(x, y + score.GetDistanceBetweenStaveLines());
                topPath.LineTo(x, y + score.GetDistanceBetweenStaveLines() - 2 * StaveLineHalfWidth);
                canvas.DrawPath(topPath, lineWidth);

                topPath = new GraphicPath();
                topPath.Reset();
                topPath.MoveTo(middle2, ye + score.GetDistanceBetweenStaveLines() - slope * (xe - middle2) - 2 * StaveLineHalfWidth);
                topPath.LineTo(xe, ye + score.GetDistanceBetweenStaveLines() - 2 * StaveLineHalfWidth);
                topPath.LineTo(xe, ye + score.GetDistanceBetweenStaveLines());
                topPath.LineTo(middle2, ye + score.GetDistanceBetweenStaveLines() - slope * (xe - middle2));
                topPath.LineTo(middle2, ye + score.GetDistanceBetweenStaveLines() - slope * (xe - middle2) - 2 * StaveLineHalfWidth);
                canvas.DrawPath(topPath, lineWidth);
            }
        }

        if (position == 0)
            canvas.DrawText(text, (x + xe) / 2 - w / 2, (y + ye) / 2 - 1.2f * score.GetDistanceBetweenStaveLines(), score.Font);
        else
            canvas.DrawText(text, (x + xe) / 2 - w / 2, (y + ye) / 2 + 0.8f * score.GetDistanceBetweenStaveLines(), score.Font);

        //score.Font.SetMaskFilter(null);
    }

}